﻿using Ndns.ServerHost.Abstractions;
using System;
using System.Collections.Generic;
using System.Net;

namespace Ndns.Net
{
    public class CompositeDnsServerBuilder : ICompositeDnsServerBuilder
    {
        public static ICompositeDnsServerBuilder Create()
        {
            return new CompositeDnsServerBuilder();
        }

        private IDnsRequestHandler _handler;
        private List<IDnsServer> _servers = new List<IDnsServer>();

        public ICompositeDnsServerBuilder SetHandler(IDnsRequestHandler handler)
        {
            if (handler == null)
                throw new ArgumentNullException(nameof(handler));
            _handler = handler;
            return this;
        }

        public ICompositeDnsServerBuilder Add(IDnsServer server)
        {
            if (server == null)
                throw new ArgumentNullException(nameof(server));
            if (server.State == DnsServerState.Running)
                throw new InvalidOperationException();
            if (_servers.Contains(server))
                throw new InvalidOperationException();

            _servers.Add(server);
            return this;
        }

        public IDnsServer Build()
        {
            return new CompositeDnsServer(_servers, _handler);
        }
    }

    internal class CompositeDnsServer : IDnsServer, IDisposable
    {
        private IDnsRequestHandler _handler;
        private IDnsServer[] _servers;

        internal CompositeDnsServer(List<IDnsServer> servers, IDnsRequestHandler handler)
        {
            if (servers == null)
                throw new ArgumentNullException(nameof(servers));
            if (handler == null)
                throw new ArgumentNullException(nameof(handler));

            _servers = servers.ToArray();
            _handler = handler;
        }

        public DnsProtocol Protocol => DnsProtocol.Unknown;

        public EndPoint LocalEndPoint => throw new NotSupportedException();

        public DnsServerState State { get; private set; }

        public object Tag { get; set; }

        public IDnsRequestHandler Handler => _handler;

        public void SetHandler(IDnsRequestHandler handler)
        {
            if (handler == null)
                throw new ArgumentNullException(nameof(handler));

            _handler = handler;
        }

        public void Start()
        {
            if (disposedValue)
                throw new ObjectDisposedException(nameof(DnsUdpServer));
            if (_handler == null)
                throw new InvalidOperationException();
            if (State == DnsServerState.Running)
                throw new InvalidOperationException();

            //设置Handler
            foreach (var server in _servers)
            {
                server.SetHandler(_handler);
            }

            //启动
            foreach (var server in _servers)
            {
                server.Start();
            }

            //检查是否启动成功
            bool isSuccess = true;
            foreach (var server in _servers)
            {
                if (server.State != DnsServerState.Running)
                {
                    isSuccess = false;
                    break;
                }
            }
            
            if (isSuccess)
            {
                State = DnsServerState.Running;
            }
            else
            {
                State = DnsServerState.Error;
                foreach (var server in _servers)
                {
                    server.Stop();
                }
            }
        }

        public void Stop()
        {
            if (disposedValue)
                throw new ObjectDisposedException(nameof(DnsUdpServer));

            if (State == DnsServerState.Running)
            {
                foreach (var server in _servers)
                {
                    server.Stop();
                }
            }
            State = DnsServerState.Stopped;
        }

        #region IDisposable Support
        private bool disposedValue = false; // 要检测冗余调用

        protected virtual void Dispose(bool disposing)
        {
            if (!disposedValue)
            {
                if (disposing)
                {
                    // 释放托管状态(托管对象)。
                    foreach (var server in _servers)
                    {

                        (server as IDisposable)?.Dispose();
                    }
                }

                // 释放未托管的资源(未托管的对象)并在以下内容中替代终结器。
                // 将大型字段设置为 null。
                for (int i = 0; i < _servers.Length; i++)
                {
                    _servers[i] = null;
                }

                disposedValue = true;
            }
        }

        // 添加此代码以正确实现可处置模式。
        public void Dispose()
        {
            // 请勿更改此代码。将清理代码放入以上 Dispose(bool disposing) 中。
            Dispose(true);
        }
        #endregion
    }
}
